package br3akr.DeadlyDinnerParty.Server.Actions;

import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TimerTask;

import br3akr.DeadlyDinnerParty.Server.Engine.Server;
import br3akr.DeadlyDinnerParty.Server.Engine.Session;
import br3akr.DeadlyDinnerParty.Server.Engine.TimedActionTask;
import br3akr.DeadlyDinnerParty.Server.Exceptions.DeadlyDinnerPartyException;
import br3akr.DeadlyDinnerParty.Server.World.Area;
import br3akr.DeadlyDinnerParty.Server.World.Body;
import br3akr.DeadlyDinnerParty.Server.World.GameCharacter;
import br3akr.DeadlyDinnerParty.Server.World.IsHidable;
import br3akr.DeadlyDinnerParty.Server.World.Item;

public class HideAction extends Action implements TimerAction {
	boolean actionComplete;
    private ActionResponse actionResponse;
	private static final int START  = 1;
	private static final int CONTINUING = 2;
	private static final int COMPLETE = 3;
	private int curStep = START;
	private Area hidingLocation = null;
	private IsHidable hidable = null;
	private String currentDescription = null;
	TimerTask task = null;
	
    public static final Set<String> keywords;
	static
	{
		Set<String>tempKeywords = new HashSet<String>();
		tempKeywords.add("Hide");
		tempKeywords.add("Hi");
		keywords = Collections.unmodifiableSet(tempKeywords);
	}
    
    public HideAction() {
        super("Hide", false);
    }
    
    public ActionResponse doAction(String action, Session session) throws DeadlyDinnerPartyException {
    	if (curStep == START) {
			if (action == null) {
				actionComplete = true;
				throw new DeadlyDinnerPartyException ("No action found.");
			}
			if (session == null) {
				actionComplete = true;
				throw new DeadlyDinnerPartyException ("No session found.");
			}
			
	    	StringTokenizer tokenizedAction = new StringTokenizer(action);
	    	String param1 = null;
	    	
	    	if (tokenizedAction.hasMoreTokens()) {
	    		param1 = tokenizedAction.nextToken();
	    	}
	    	
	    	param1 = action.substring(action.indexOf(param1) + param1.length()).trim();
	    	
			GameCharacter actor = session.getCharacter();
			
			if (actor == null) {
				actionComplete = true;
				throw new DeadlyDinnerPartyException ("No character found for your session.");
			}
	    	
	    	actionResponse = new ActionResponse();
	    	actionResponse.setActingCharacter(session.getCharacter());
	    	Area location = session.getCharacter().getLocation();
	    	Set<GameCharacter> localOnlookers = location.getAreaOnlookers(session.getCharacter(), null);
	    	actionResponse.addAffectedArea(location);
	    	hidingLocation = actor.getLocation();
	    	
	    	if (param1 != null) {
		    	hidable = location.getBody(param1);
		    	if (hidable == null) {
		    		hidable = actor.getInventoryItem(param1);
		    	}
		    	GameCharacter hidFrom = null;
		    	
		    	if (hidable != null && !hidable.isHiddenFrom(actor)) {
		    		for (Session s : Server.world.getOnlinePlayers()) {
		    			hidFrom = s.getCharacter();
		    			if (!hidFrom.equals(actor) && !location.getCharacters().contains(hidFrom)) {
		    				hidable.addHiddenFrom(hidFrom);
		    			}
		    		}
		    	} else {
		    		actionComplete = true;
		    		throw new DeadlyDinnerPartyException ("There is nothing here you can hide called " + param1);
		    	}
	    	} else {
	    		hidable = actor;
	    	}
			
	    	task = new TimedActionTask(session, this);
			Timer timer = new Timer();
			
	    	if (hidable instanceof Body) {
	    		Body body = (Body) hidable;
				actionResponse.addOnlookers(localOnlookers, actor.getName() + " begins stuffing the body of " + body.getCharacter().getName() + " in a dark corner!");
				actionResponse.setActingCharacterDescription("You begin stuffing the body of " + body.getCharacter().getName() + " in a dark corner.");
				timer.schedule(task, 1000);
	    	} else if (hidable instanceof Item) {
	    		Item item = (Item) hidable;
				actionResponse.addOnlookers(localOnlookers, actor.getName() + " begins hiding something here.");
				actionResponse.setActingCharacterDescription("You begin finding a place to hide " + item.getName() + ".");
				timer.schedule(task, 1000);
	    	} else if (hidable instanceof GameCharacter) {
				actionResponse.addOnlookers(localOnlookers, actor.getName() + " begins looking for somewhere to hide here.");
				actionResponse.setActingCharacterDescription("You begin finding a place to hide.");
				timer.schedule(task, 1000);
	    	}
	    	currentDescription = actor.getName() + " is searching the room for something.";
	    	curStep = CONTINUING;
    	} else if (curStep == CONTINUING) {
    		if (action.equalsIgnoreCase("QUIT") || action.equalsIgnoreCase("Q") || action.equalsIgnoreCase("STOP") || action.equalsIgnoreCase("DONE")) {
    			actionComplete = true;
        		Set<GameCharacter> localOnlookers = hidingLocation.getAreaOnlookers(session.getCharacter(), null);
    			GameCharacter actor = session.getCharacter();
    			
    			if (actor == null) {
    				actionComplete = true;
    				throw new DeadlyDinnerPartyException ("No character found for your session.");
    			}
    			
    	    	if (hidable instanceof Body) {
    	    		Body body = (Body) hidable;
    				actionResponse.addOnlookers(localOnlookers, actor.getName() + " stops stuffing the body of " + body.getCharacter().getName() + " in a dark corner, and it falls on the ground with a thud.");
    				actionResponse.setActingCharacterDescription("You stop stuffing the body of " + body.getCharacter().getName() + " in a dark corner and it falls on the ground with a thud.");
    	    	} else if (hidable instanceof Item) {
    	    		Item item = (Item) hidable;
    				actionResponse.addOnlookers(localOnlookers, actor.getName() + " stops trying to hide something here.");
    				actionResponse.setActingCharacterDescription("You stop finding a place to hide " + item.getName() + ".");
    	    	} else if (hidable instanceof GameCharacter) {
    				actionResponse.addOnlookers(localOnlookers, actor.getName() + " stops looking for somewhere to hide here.");
    				actionResponse.setActingCharacterDescription("You stop finding a place to hide.");
    	    	}
    			task.cancel();
    		}
    	} else if (curStep == COMPLETE) {
    		actionComplete = true;
    		Set<GameCharacter> localOnlookers = hidingLocation.getAreaOnlookers(session.getCharacter(), null);
			GameCharacter actor = session.getCharacter();
			
			if (actor == null) {
				actionComplete = true;
				throw new DeadlyDinnerPartyException ("No character found for your session.");
			}
	    	if (hidable instanceof Body) {
	    		Body body = (Body) hidable;
				actionResponse.addOnlookers(localOnlookers, actor.getName() + " finishes stuffing the body of " + body.getCharacter().getName() + " in a dark corner.");
				actionResponse.setActingCharacterDescription("You finish stuffing the body of " + body.getCharacter().getName() + " in a dark corner.");
	    	} else if (hidable instanceof Item) {
	    		Item item = (Item) hidable;
	    		actor.removeItem(item);
	    		hidingLocation.addItem(item);
				actionResponse.addOnlookers(localOnlookers, actor.getName() + " finishes hiding something here.");
				actionResponse.setActingCharacterDescription("You finish finding a place to hide " + item.getName() + ".");
	    	} else if (hidable instanceof GameCharacter) {
				actionResponse.addOnlookers(localOnlookers, actor.getName() + " hides here.");
				actionResponse.setActingCharacterDescription("You are now hidden.");
	    	}
	    	
	    	GameCharacter gc = null;
	    	
	    	for (Session s : Server.world.getOnlinePlayers()) {
	    		gc = s.getCharacter();

	    		if (hidingLocation.getCharacter(gc.getName()) == null) {
	    			hidable.addHiddenFrom(gc);
	    		}
	    	}
    	}
        return actionResponse;
    }
	
    public ActionResponse getActionResponse() {
		return actionResponse;
	}
    
    public Set<String> getKeywords() {
        return keywords;
    }

	@Override
	public void nextStep() {
		if (curStep == CONTINUING) {
			curStep = COMPLETE;
			actionComplete = true;
		}
		
		if (curStep == COMPLETE) {
			actionComplete = true;
		}
	}

	@Override
	public boolean isComplete() {
		return actionComplete;
	}

	@Override
	public String getCurrentDescription() {
		return currentDescription;
	}

	@Override
	public long timeLeft() {
		return task.scheduledExecutionTime() - (new Date()).getTime();
	}
}